// 确保文件以UTF-8编码保存
#include "CLink/Utils/ResponseUtils.h"
// 确保文件以UTF-8编码保存
#include <Poco/FileStream.h>
#include <Poco/StreamCopier.h>
#include <Poco/DeflatingStream.h>
#include <Poco/DateTimeParser.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Format.h>
#include <Poco/String.h>
#include <fstream>

namespace CLink
{
namespace HttpResponseUtils
{

// 发送文本响应
void sendText(Poco::Net::HTTPServerResponse &response,
                const std::string &text,
                int statusCode,
                const std::string &contentType,
                bool compress)
{
    sendResponse(response, statusCode, contentType, [&text](std::ostream &out)
                    { out << text; }, compress);
}

// 发送HTML响应
void sendHtml(Poco::Net::HTTPServerResponse &response,
                const std::string &html,
                int statusCode,
                bool compress)
{
    sendText(response, html, statusCode, ContentType::TEXT_HTML, compress);
}

// 发送JSON响应
void sendJson(Poco::Net::HTTPServerResponse &response,
                const Poco::JSON::Object &json,
                int statusCode,
                bool compress)
{
    sendResponse(response, statusCode, ContentType::APPLICATION_JSON, [&json](std::ostream &out)
        {
            json.stringify(out);
        }, compress);
}

// 发送JSON数组响应
void sendJsonArray(Poco::Net::HTTPServerResponse &response,
                    const Poco::JSON::Array &jsonArray,
                    int statusCode,
                    bool compress)
{
    sendResponse(response, statusCode, ContentType::APPLICATION_JSON, [&jsonArray](std::ostream &out)
                    { jsonArray.stringify(out); }, compress);
}

// 发送错误信息（JSON格式）
void sendErrorJson(Poco::Net::HTTPServerResponse &response,
                    int statusCode,
                    const std::string &errorCode,
                    const std::string &message,
                    const std::vector<ErrorDetail> &details)
{
    Poco::JSON::Object root;
    root.set("error", errorCode);
    root.set("message", message);

    if (!details.empty())
    {
        Poco::JSON::Array detailsArray;
        for (const auto &detail : details)
        {
            Poco::JSON::Object detailObj;
            detailObj.set("code", detail.code);
            detailObj.set("field", detail.field);
            detailObj.set("message", detail.message);
            detailsArray.add(detailObj);
        }
        root.set("details", detailsArray);
    }

    setStatus(response, statusCode);
    sendJson(response, root);
}

// 获取文件MIME类型
std::string getMimeType(const std::string &filePath)
{
    static const std::map<std::string, std::string> mimeTypes = {
        {".html", ContentType::TEXT_HTML},
        {".htm", ContentType::TEXT_HTML},
        {".css", ContentType::TEXT_CSS},
        {".js", ContentType::TEXT_JAVASCRIPT},
        {".mjs", ContentType::APPLICATION_JAVASCRIPT},
        {".json", ContentType::APPLICATION_JSON},
        {".xml", ContentType::APPLICATION_XML},
        {".txt", ContentType::TEXT_PLAIN},
        {".csv", ContentType::TEXT_CSV},
        {".png", ContentType::IMAGE_PNG},
        {".jpg", ContentType::IMAGE_JPEG},
        {".jpeg", ContentType::IMAGE_JPEG},
        {".gif", ContentType::IMAGE_GIF},
        {".svg", ContentType::IMAGE_SVG},
        {".pdf", ContentType::APPLICATION_PDF},
        {".zip", ContentType::APPLICATION_ZIP},
        {".woff", ContentType::FONT_WOFF},
        {".woff2", ContentType::FONT_WOFF2}};

    std::string ext = Poco::toLower(Poco::Path(filePath).getExtension());
    if (!ext.empty() && ext[0] != '.')
    {
        ext = "." + ext;
    }

    auto it = mimeTypes.find(ext);
    if (it != mimeTypes.end())
    {
        return it->second;
    }
    return ContentType::APPLICATION_OCTET_STREAM;
}

// 计算ETag
std::string computeETag(const std::string &filePath, off_t fileSize, const Poco::Timestamp &modified)
{
    Poco::File file(filePath);
    if (!file.exists())
        return "";

    std::string etag = Poco::format("\"%XZ-%X\"", fileSize, modified.epochTime());
    return etag;
}

// 解析HTTP日期
Poco::Timestamp parseHttpDate(const std::string &httpDate)
{
    int tzd;
    return Poco::DateTimeParser::parse(Poco::DateTimeFormat::HTTP_FORMAT, httpDate, tzd).timestamp();
}

// 发送文件内容
void sendFileContent(const std::string &filePath, std::ostream &out)
{
    Poco::FileInputStream fis(filePath);
    Poco::StreamCopier::copyStream(fis, out);
}

// 处理范围请求
void handleRangeRequest(Poco::Net::HTTPServerResponse &response,
                        const std::string &filePath,
                        off_t fileSize,
                        const std::string &rangeHeader)
{
    // 简单实现单部分范围请求
    if (rangeHeader.compare(0, 6, "bytes=") != 0)
    {
        sendErrorJson(response, Status::BAD_REQUEST, "invalid_range",
                        "Unsupported range unit");
        return;
    }

    std::string rangeSpec = rangeHeader.substr(6);
    size_t dashPos = rangeSpec.find('-');
    if (dashPos == std::string::npos)
    {
        sendErrorJson(response, Status::BAD_REQUEST, "invalid_range",
                        "Invalid range format");
        return;
    }

    off_t start = 0, end = 0;
    try
    {
        if (dashPos == 0)
        {
            // 后缀长度格式，例如 "-500"
            off_t suffixLength = std::stol(rangeSpec);
            start = fileSize - suffixLength;
            end = fileSize - 1;
        }
        else
        {
            // 标准范围格式，例如 "0-499"
            start = std::stol(rangeSpec.substr(0, dashPos));
            if (dashPos < rangeSpec.size() - 1)
            {
                end = std::stol(rangeSpec.substr(dashPos + 1));
            }
            else
            {
                end = fileSize - 1;
            }
        }
    }
    catch (...)
    {
        sendErrorJson(response, Status::BAD_REQUEST, "invalid_range",
                        "Invalid range values");
        return;
    }

    // 验证范围
    if (start < 0 || end >= fileSize || start > end)
    {
        sendErrorJson(response, Status::RANGE_NOT_SATISFIABLE, "invalid_range",
                        Poco::format("Invalid range requested. File size: %ld", fileSize));
        response.set("Content-Range",
                        Poco::format("bytes */%ld", fileSize));
        return;
    }

    // 设置部分内容响应
    setStatus(response, Status::PARTIAL_CONTENT);
    response.setContentLength(end - start + 1);
    response.set("Content-Range",
                    Poco::format("bytes %ld-%ld/%ld", start, end, fileSize));

    // 发送范围内容
    std::ostream &out = response.send();
    Poco::FileInputStream fis(filePath);
    fis.seekg(start, std::ios::beg);

    const size_t BUFFER_SIZE = 65536;
    char buffer[BUFFER_SIZE];
    off_t remaining = end - start + 1;

    while (remaining > 0)
    {
        off_t chunk = (remaining > BUFFER_SIZE) ? static_cast<off_t>(BUFFER_SIZE) : remaining;
        fis.read(buffer, static_cast<std::streamsize>(chunk));
        out.write(buffer, static_cast<std::streamsize>(chunk));
        remaining -= chunk;
    }
}

// 发送文件
void sendFile(Poco::Net::HTTPServerResponse &response,
                const std::string &filePath,
                const std::string &attachmentName,
                const Headers &additionalHeaders,
                const std::string &rangeHeader,
                bool compress)
{
    Poco::File file(filePath);
    if (!file.exists())
    {
        sendErrorJson(response, Status::NOT_FOUND, "file_not_found",
                        Poco::format("File %s not found", filePath));
        return;
    }

    if (file.isDirectory())
    {
        sendErrorJson(response, Status::FORBIDDEN, "access_denied",
                        Poco::format("%s is a directory", filePath));
        return;
    }

    std::string mimeType = getMimeType(filePath);
    Poco::Timestamp modifiedTime = file.getLastModified();
    off_t fileSize = static_cast<off_t>(file.getSize());

    // 设置ETag和Last-Modified
    std::string etag = computeETag(filePath, fileSize, modifiedTime);
    setETag(response, etag);
    setLastModified(response, modifiedTime);

    // 处理部分内容请求 (Range requests)
    if (!rangeHeader.empty() && fileSize > 0)
    {
        handleRangeRequest(response, filePath, fileSize, rangeHeader);
        return;
    }

    // 处理If-Modified-Since条件请求
    std::string ifModifiedSince = response.get("If-Modified-Since", "");
    if (!ifModifiedSince.empty() && modifiedTime <= parseHttpDate(ifModifiedSince))
    {
        setStatus(response, Status::NOT_MODIFIED);
        response.send();
        return;
    }

    // 设置标准文件头
    setStatus(response, Status::OK);
    setContentType(response, mimeType);
    response.setContentLength(fileSize);
    setHeaders(response, additionalHeaders);

    if (!attachmentName.empty())
    {
        std::string contentDisposition = "attachment; filename=\"" + attachmentName + "\"";
        setHeader(response, "Content-Disposition", contentDisposition);
    }

    // 发送文件
    if (compress)
    {
        std::ostream &rawOut = response.send();
        Poco::SharedPtr<std::ostream> pOut(&rawOut);
        Poco::DeflatingOutputStream deflater(*pOut, Poco::DeflatingStreamBuf::STREAM_GZIP);
        sendFileContent(filePath, deflater);
        deflater.close();
    }
    else
    {
        std::ostream &out = response.send();
        sendFileContent(filePath, out);
    }
}

// 重定向
void redirect(Poco::Net::HTTPServerResponse &response,
                const std::string &location,
                bool permanent,
                bool seeOther)
{
    int status = Status::FOUND; // 302 Found

    if (permanent)
    {
        status = Status::MOVED_PERMANENTLY; // 301 Moved Permanently
    }
    else if (seeOther)
    {
        status = Status::SEE_OTHER; // 303 See Other
    }

    setStatus(response, status);
    setHeader(response, "Location", location);

    Poco::JSON::Object json;
    json.set("status", "redirect");
    json.set("location", location);
    json.set("message", "Redirecting to " + location);

    sendJson(response, json, status);
}

// 发送204 No Content响应
void sendNoContent(Poco::Net::HTTPServerResponse &response,
                    const Headers &headers)
{
    setStatus(response, Status::NO_CONTENT);
    setHeaders(response, headers);
    response.send();
}

// 发送二进制数据
void sendBinary(Poco::Net::HTTPServerResponse &response,
                const char *data,
                size_t length,
                const std::string &contentType,
                int statusCode,
                bool compress)
{
    sendResponse(response, statusCode, contentType, [data, length](std::ostream &out)
                    { out.write(data, static_cast<std::streamsize>(length)); }, compress);
}

// 设置内容分发网络标头
void setCDNHeaders(Poco::Net::HTTPServerResponse &response,
                    const std::string &cacheId,
                    const std::string &edgeTraceId)
{
    setHeader(response, "X-Cache", cacheId);
    setHeader(response, "X-Edge-Trace-ID", edgeTraceId);
}

// 设置速率限制标头
void setRateLimitHeaders(Poco::Net::HTTPServerResponse &response,
                            int limit,
                            int remaining,
                            int resetTime)
{
    setHeader(response, "X-RateLimit-Limit", std::to_string(limit));
    setHeader(response, "X-RateLimit-Remaining", std::to_string(remaining));
    setHeader(response, "X-RateLimit-Reset", std::to_string(resetTime));
}

} // namespace HttpResponseUtils
}